package com.joysuch.wwyt.workflow.api.service.impl;

import cn.hutool.http.HttpException;
import cn.hutool.http.HttpRequest;
import cn.zlg.common.util.CollectionUtils;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.gson.reflect.TypeToken;
import com.joysuch.wwyt.config.RedisClient;
import com.joysuch.wwyt.core.entity.BaseConfig;
import com.joysuch.wwyt.core.enums.BaseConfigCodes;
import com.joysuch.wwyt.core.enums.Status;
import com.joysuch.wwyt.core.exception.ApiCoreException;
import com.joysuch.wwyt.core.service.BaseConfigService;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.log.service.ApiLogService;
import com.joysuch.wwyt.util.GsonUtils;
import com.joysuch.wwyt.workflow.api.bean.*;
import com.joysuch.wwyt.workflow.api.service.PersonTrajectoryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class PersonTrajectoryImpl implements PersonTrajectoryService {

    @Autowired
    private BaseConfigService baseConfigService;

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private ApiLogService apiLogService;

    @Autowired
    private PersonTrajectoryService personTrajectoryService;


    @Override
    public String getTokenFromCache() throws ApiCoreException {
        Long tenantId = Context.getCurrentTenantId();
        String orgCode = Context.getCompanyCode();

        return getTokenFromCache(tenantId,orgCode);
    }

    @Override
    public String getTokenFromCache(Long tenentId, String orgCode) throws ApiCoreException {
        String redisKey = String.format(BaseConfigCodes.OPEN_SERVICE_TOKEN_REDIS_KEY, tenentId, orgCode);
        String token = redisClient.get(redisKey);
        if (StringUtils.isNotEmpty(token)) {
            return token;
        } else {
            token = this.getOpenServiceToken(tenentId,orgCode);
            if (token != null) {
                redisClient.setEx(redisKey, token, 60, TimeUnit.MINUTES);
                return token;
            }
        }
        return null;
    }

    public String getOpenServiceToken(Long tenentId, String orgCode) throws ApiCoreException {
        BaseConfig ipConfig = baseConfigService.findConfig(tenentId, orgCode, BaseConfigCodes.OPEN_SERVICE_SERVER_URL);
        BaseConfig secretConfig = baseConfigService.findConfig(tenentId, orgCode, BaseConfigCodes.LOCATE_SERVER_SECRET);
        BaseConfig tokenApi = baseConfigService.findConfig(tenentId, orgCode, BaseConfigCodes.OPEN_SERVICE_TOKEN_API);
        if (ipConfig != null && secretConfig != null && tokenApi != null) {
            String finalUrl;
            String ipPort = ipConfig.getValue();
            String loginSecret = secretConfig.getValue();
            String apiName = tokenApi.getValue();
            //默认http
            Map<String, Object> param = new HashMap<>();
            param.put("licence", loginSecret);
            String tempUrl;
            String response;
            if (!ipPort.contains("http")) {
                tempUrl = "http://%s%s";
                finalUrl = String.format(tempUrl, ipPort, apiName);
            } else {
                tempUrl = ipPort + "%s";
                finalUrl = String.format(tempUrl, apiName);
            }
            try {
                response = HttpRequest.post(finalUrl).body(JSONObject.toJSONString(param)).execute().body();
                Result<TokenResp> result = GsonUtils.fromJson(response, new TypeToken<Result<TokenResp>>() {
                }.getType());
                if (result.getErrorCode() == Result.SUCCESS && result.getData() != null) {
                    log.info("open service licence获取的token: tempUrl{}, loginSecret{},token{}", tempUrl, loginSecret, result.getData().getToken());
                    apiLogService.saveApiLog(finalUrl, null, null, null, JSONObject.toJSONString(param), response, Status.SUCCESS.getCode(), null);
                    return result.getData().getToken();
                } else {
                    apiLogService.saveApiLog(finalUrl, null, null, null, JSONObject.toJSONString(param), response, Status.FAILED.getCode(), null);
                }
            } catch (HttpException e) {
                throw new ApiCoreException(Status.PERSON_TRAJECTORY_CONNECTION_ANOMALY);
            }
        } else {
            log.info("getPersonTrajectoryPoints Configuration missing, please check");
            throw new ApiCoreException(Status.PERSON_TRAJECTORY_ERROR);
        }
        return null;
    }

    public String getOpenServiceToken() throws ApiCoreException {
      return getOpenServiceToken(Context.getCurrentTenantId(), Context.getCompanyCode());
    }

    @Override
    public List<PersonTrajectoryResp> getPersonTrajectoryPoints(String tagMacAddress, long startTime,long endTime, String taskCode, String requestId) throws ApiCoreException {
        BaseConfig personTrajectoryApi = baseConfigService.findFirstConfig(BaseConfigCodes.OPEN_SERVICE_PERSON_TRAJECTORY_API);
        TrajectoryPointHttpParam param = getPersonTrajectoryHttpParam(tagMacAddress, personTrajectoryApi);
        param.setStartTime(startTime);
        param.setEndTime(endTime);
        String token = personTrajectoryService.getTokenFromCache();
        param.setToken(token);
        return getPersonTrajectoryRespByHttp(param, taskCode, requestId);
    }

    @Override
    public List<PersonTrajectoryResp> getPersonTrajectoryPoints(String tagMacAddress, long lastPointTime, String taskCode, String requestId) throws ApiCoreException {
        int defaultTracingTimeRange = getTracingTimeConfig();
        long startTime = lastPointTime - defaultTracingTimeRange * 1000L;
        BaseConfig personTrajectoryApi = baseConfigService.findFirstConfig(BaseConfigCodes.OPEN_SERVICE_PERSON_TRAJECTORY_API);
        TrajectoryPointHttpParam param = getPersonTrajectoryHttpParam(tagMacAddress, personTrajectoryApi);
        param.setStartTime(startTime);
        param.setEndTime(lastPointTime);
        String token = personTrajectoryService.getTokenFromCache();
        param.setToken(token);
        return getPersonTrajectoryRespByHttp(param, taskCode, requestId);
    }

    private int getTracingTimeConfig() throws ApiCoreException {
        BaseConfig tracingTimeConfig = baseConfigService.findFirstConfig(BaseConfigCodes.PERSON_TRAJECTORY_TIME_FRAME);
        if (tracingTimeConfig == null) {
            log.info("getPersonTrajectoryPoints tracingTimeConfig  missing, please check");
            throw new ApiCoreException(Status.PERSON_TRAJECTORY_ERROR);
        }
        return Integer.parseInt(tracingTimeConfig.getValue());
    }

    public TrajectoryPointHttpParam getPersonTrajectoryHttpParam(final String tagMacAddress, BaseConfig configApi) {
        BaseConfig ipConfig = baseConfigService.findConfig(BaseConfigCodes.OPEN_SERVICE_SERVER_URL);
        BaseConfig secretConfig = baseConfigService.findConfig(BaseConfigCodes.LOCATE_SERVER_SECRET);
        BaseConfig buildIdConfig = baseConfigService.findConfig(BaseConfigCodes.LOCATE_CURRENT_BUILD_ID);
        BaseConfig locationTypeConfig = baseConfigService.findConfig(BaseConfigCodes.PERSON_TRAJECTORY_LOCAL_TYPE);
        boolean hadIp = Objects.nonNull(ipConfig) && StringUtils.isNotBlank(ipConfig.getValue());
        boolean hadSecret = Objects.nonNull(secretConfig) && StringUtils.isNotBlank(secretConfig.getValue());
        boolean hadBuildIngId = Objects.nonNull(buildIdConfig) && StringUtils.isNotBlank(buildIdConfig.getValue());

        if (hadIp && hadSecret && hadBuildIngId && configApi != null) {
            return TrajectoryPointHttpParam.builder()
                    .tagMacAddress(tagMacAddress)
                    .buildId(buildIdConfig.getValue())
                    .apiName(configApi.getValue())
                    .ipPort(ipConfig.getValue())
                    .locationType(locationTypeConfig != null && StringUtils.isNotEmpty(locationTypeConfig.getValue()) ? locationTypeConfig.getValue() : null)
                    .build();
        } else {
            log.info("getPersonTrajectoryPoints Configuration missing, please check");
            throw new IllegalArgumentException(Status.CAN_NOT_ACCESS_OPEN_SERVICE.getMsg());
        }
    }

    private List<PersonTrajectoryResp> getPersonTrajectoryRespByHttp(TrajectoryPointHttpParam param, String taskCode, String requestId) {
        String body = JSONObject.toJSONString(TrajectoryPointReq.builder()
                .buildId(param.getBuildId())
                .mac(param.getTagMacAddress())
                .locationType(param.getLocationType())
                .startTime(param.getStartTime())
                .endTime(param.getEndTime()).build());
        log.info(">>>>>>>> Get person trajectory points body param: " + body);
        long start = System.currentTimeMillis();
        String finalUrl = getUrl(param.getIpPort(), param.getApiName(), param.getToken());
        String response = HttpRequest.post(finalUrl).body(body)
                .execute().body();
        long end = System.currentTimeMillis();
        long time = end - start;
        log.info(">>>>>>>> open service request" + " -> " + " cost " + time + "ms");
//        log.info(">>>>>>>> Get person trajectory points response: " + response);
        ResultDataList<PersonTrajectoryResp> result = GsonUtils.fromJson(response, new TypeToken<ResultDataList<PersonTrajectoryResp>>() {
        }.getType());
        if (result.getErrorCode() == Result.SUCCESS && CollectionUtils.isNotEmpty(result.getData())) {
            apiLogService.saveApiLog(finalUrl, taskCode, null, param.getTagMacAddress(), body, response, Status.SUCCESS.getCode(), requestId);
            return result.getData();
        }
        apiLogService.saveApiLog(finalUrl, taskCode, null, param.getTagMacAddress(), body, response, Status.FAILED.getCode(), requestId);
        return Lists.newArrayList();
    }

    private String getUrl(String ipPort, String apiUrl, String token) {
        //默认http
        String finalUrl;
        String tempUrl;
        if (!ipPort.contains("http")) {
            tempUrl = "http://%s/%s?accessToken=%s";
            finalUrl = String.format(tempUrl, ipPort, apiUrl, token);
        } else {
            tempUrl = ipPort + "%s?accessToken=%s";
            finalUrl = String.format(tempUrl, apiUrl, token);
        }
        return finalUrl;
    }

    @Override
    public TrajectoryLastLocationResp getLastLocation(String sn, String taskCode, String requestId) throws ApiCoreException {
        BaseConfig lastLocationConfig = baseConfigService.findFirstConfig(BaseConfigCodes.PERSON_TRAJECTORY_LAST_LOCATION);
        if (lastLocationConfig == null) {
            log.info("baseConfig:personTrajectoryLastLocation is null, please check");
            throw new IllegalArgumentException(Status.PERSON_TRAJECTORY_ERROR.getMsg());
        }
        //参数
        TrajectoryPointHttpParam param = getPersonTrajectoryHttpParam(sn, lastLocationConfig);
        String token = personTrajectoryService.getTokenFromCache();
        String finalUrl = getUrl(param.getIpPort(), lastLocationConfig.getValue(), token);
        TrajectoryPointLastLocationHttpParam httpParam = new TrajectoryPointLastLocationHttpParam();
        httpParam.setMacs(Lists.newArrayList(sn));
        httpParam.setTimePeriod(-1);
        String body = JSONObject.toJSONString(httpParam);
        //请求
        String response = HttpRequest.post(finalUrl).body(body).execute().body();
        ResultDataList<TrajectoryLastLocationResp> result = GsonUtils.fromJson(response, new TypeToken<ResultDataList<TrajectoryLastLocationResp>>() {
        }.getType());
        if (result.getErrorCode() == Result.SUCCESS && CollectionUtils.isNotEmpty(result.getData())) {
            apiLogService.saveApiLog(finalUrl, taskCode, null, param.getTagMacAddress(), body, response, Status.SUCCESS.getCode(), requestId);
            return result.getData().get(0);
        } else {
            if (!org.springframework.util.CollectionUtils.isEmpty(result.getErrorMsg())) {
                log.error("开放平台获取最近一次点位错误 code: " + result.getErrorCode() + " errorMessage:" + result.getErrorMsg());
            }
            apiLogService.saveApiLog(finalUrl, taskCode, null, param.getTagMacAddress(), body, response, Status.FAILED.getCode(), requestId);
            throw new IllegalArgumentException(Status.CAN_NOT_ACCESS_OPEN_SERVICE.getMsg());
        }
    }

}
